#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <pthread.h>
#include <time.h>

// 全局配置
#define MAX_CONNECTIONS 10000
#define BUFFER_SIZE 8192
#define MAX_USERNAME_LEN 64
#define MAX_PASSWORD_LEN 64
#define MAX_RESOURCE_LEN 256

// SSL VPN网关版本
#define SSLVPN_VERSION "1.0.0"

// 连接状态枚举
typedef enum {
    CONN_STATE_DISCONNECTED,
    CONN_STATE_CONNECTING,
    CONN_STATE_AUTHENTICATING,
    CONN_STATE_AUTHENTICATED,
    CONN_STATE_ESTABLISHED,
    CONN_STATE_CLOSING
} connection_state_t;

// 用户身份信息结构
typedef struct {
    char username[MAX_USERNAME_LEN];
    char password[MAX_PASSWORD_LEN];
    char role[32];
    int is_active;
    time_t last_login;
} user_t;

// 资源访问策略结构
typedef struct {
    char resource[MAX_RESOURCE_LEN];
    char allowed_roles[1024]; // 逗号分隔的角色列表
    int read_only;
    int allow_download;
} resource_policy_t;

// 会话信息结构
typedef struct {
    int session_id;
    user_t* user;
    time_t create_time;
    time_t last_activity;
    char client_ip[16];
    char tunnel_ip[16];
    SSL* ssl;
} session_t;

// 连接信息结构
typedef struct {
    int conn_id;
    int client_fd;
    SSL* ssl;
    connection_state_t state;
    session_t* session;
    time_t last_packet_time;
    int mode; // 0: 代理模式, 1: 隧道模式
} connection_t;

// SSL VPN网关结构
typedef struct {
    int server_fd;
    SSL_CTX* ssl_ctx;
    connection_t connections[MAX_CONNECTIONS];
    session_t sessions[MAX_CONNECTIONS];
    user_t* users;
    int user_count;
    resource_policy_t* policies;
    int policy_count;
    pthread_mutex_t lock;
    int running;
} sslvpn_gateway_t;

// 全局网关实例
sslvpn_gateway_t gateway;

// 初始化SSL库
void init_ssl() {
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
}

// 清理SSL库
void cleanup_ssl() {
    EVP_cleanup();
}

// 创建SSL上下文
SSL_CTX* create_ssl_context(const char* cert_file, const char* key_file) {
    const SSL_METHOD* method;
    SSL_CTX* ctx;

    method = TLS_server_method();
    ctx = SSL_CTX_new(method);
    if (!ctx) {
        perror("无法创建SSL上下文");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    // 设置证书和私钥
    if (SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    // 验证私钥
    if (SSL_CTX_check_private_key(ctx) != 1) {
        fprintf(stderr, "私钥与证书不匹配\n");
        exit(EXIT_FAILURE);
    }

    // 配置SSL参数
    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
    SSL_CTX_set_session_id_context(ctx, (unsigned char*)"SSLVPN_GATEWAY", strlen("SSLVPN_GATEWAY"));

    return ctx;
}

// 创建TCP套接字
int create_tcp_socket(int port) {
    int sockfd;
    struct sockaddr_in addr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("无法创建套接字");
        exit(EXIT_FAILURE);
    }

    // 设置套接字选项
    int opt = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt失败");
        exit(EXIT_FAILURE);
    }

    // 绑定地址和端口
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);

    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("绑定失败");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(sockfd, SOMAXCONN) < 0) {
        perror("监听失败");
        exit(EXIT_FAILURE);
    }

    return sockfd;
}

// 初始化网关
void init_gateway(int port, const char* cert_file, const char* key_file) {
    memset(&gateway, 0, sizeof(sslvpn_gateway_t));
    pthread_mutex_init(&gateway.lock, NULL);
    
    // 初始化SSL
    init_ssl();
    
    // 创建SSL上下文
    gateway.ssl_ctx = create_ssl_context(cert_file, key_file);
    
    // 创建TCP套接字
    gateway.server_fd = create_tcp_socket(port);
    
    // 初始化用户和策略（实际应用中应从配置文件或数据库加载）
    gateway.users = NULL;
    gateway.user_count = 0;
    gateway.policies = NULL;
    gateway.policy_count = 0;
    
    gateway.running = 1;
    
    printf("SSL VPN网关 v%s 初始化成功，监听端口: %d\n", SSLVPN_VERSION, port);
}

// 清理网关资源
void cleanup_gateway() {
    // 关闭服务器套接字
    close(gateway.server_fd);
    
    // 释放SSL上下文
    SSL_CTX_free(gateway.ssl_ctx);
    
    // 清理SSL库
    cleanup_ssl();
    
    // 释放用户和策略内存
    if (gateway.users) {
        free(gateway.users);
    }
    if (gateway.policies) {
        free(gateway.policies);
    }
    
    pthread_mutex_destroy(&gateway.lock);
    
    printf("SSL VPN网关已关闭\n");
}

// 用户认证函数
int authenticate_user(const char* username, const char* password, user_t** user_out) {
    // 实际应用中应从数据库或配置文件验证用户
    // 这里仅作为示例，实现一个简单的用户验证
    
    // 检查是否为内置测试用户
    if (strcmp(username, "admin") == 0 && strcmp(password, "admin123") == 0) {
        *user_out = (user_t*)malloc(sizeof(user_t));
        strcpy((*user_out)->username, "admin");
        strcpy((*user_out)->password, "admin123"); // 实际应用中应存储哈希值
        strcpy((*user_out)->role, "administrator");
        (*user_out)->is_active = 1;
        (*user_out)->last_login = time(NULL);
        return 1; // 认证成功
    }
    
    return 0; // 认证失败
}

// 检查资源访问权限
int check_resource_access(user_t* user, const char* resource) {
    // 实际应用中应根据策略配置检查权限
    // 这里仅作为示例，实现简单的权限检查
    
    // 管理员角色拥有所有权限
    if (strcmp(user->role, "administrator") == 0) {
        return 1;
    }
    
    // 其他角色需要根据策略检查权限
    // 此处略去具体实现
    
    return 0;
}

// 处理HTTP代理请求
void handle_http_proxy_request(connection_t* conn, const char* request) {
    char response[BUFFER_SIZE];
    char method[16], path[1024], version[16];
    
    // 解析HTTP请求行
    if (sscanf(request, "%s %s %s", method, path, version) < 3) {
        // 无效请求
        sprintf(response, "HTTP/1.1 400 Bad Request\r\nContent-Length: 15\r\n\r\nBad Request");
        SSL_write(conn->ssl, response, strlen(response));
        return;
    }
    
    // 检查用户是否有权访问该资源
    if (!check_resource_access(conn->session->user, path)) {
        sprintf(response, "HTTP/1.1 403 Forbidden\r\nContent-Length: 19\r\n\r\nAccess Forbidden");
        SSL_write(conn->ssl, response, strlen(response));
        return;
    }
    
    // 简单示例：返回成功响应
    sprintf(response, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n" 
            "<html><body><h1>SSL VPN代理访问成功</h1><p>请求路径: %s</p><p>用户: %s</p></body></html>",
            strlen("<html><body><h1>SSL VPN代理访问成功</h1><p>请求路径: </p><p>用户: </p></body></html>") + strlen(path) + strlen(conn->session->user->username),
            path, conn->session->user->username);
    
    SSL_write(conn->ssl, response, strlen(response));
}

// URL重写函数
char* rewrite_url(const char* original_url, const char* proxy_prefix, const char* target_host) {
    // 分配足够的内存存储重写后的URL
    char* rewritten_url = (char*)malloc(strlen(original_url) + strlen(proxy_prefix) + strlen(target_host) + 16);
    if (!rewritten_url) {
        return NULL;
    }
    
    // 简单示例：将原始URL重写为代理URL格式
    sprintf(rewritten_url, "%s/%s%s", proxy_prefix, target_host, original_url);
    
    return rewritten_url;
}

// 处理隧道数据
void handle_tunnel_data(connection_t* conn, const unsigned char* data, int data_len) {
    // 隧道模式下的数据处理逻辑
    // 1. 解封装数据
    // 2. 进行路由查找
    // 3. 转发数据到内部网络
    // 4. 接收内部网络响应
    // 5. 封装响应数据
    // 6. 通过SSL隧道发送给客户端
    
    // 这里仅作为示例，简化处理
    printf("接收到隧道数据，长度: %d 字节\n", data_len);
    
    // 在实际应用中，应该根据隧道协议格式解析数据包
    // 然后根据目标IP地址和端口转发到内部网络
    
    // 简单回显示例
    SSL_write(conn->ssl, data, data_len);
}

// 处理客户端连接
void* handle_client(void* arg) {
    connection_t* conn = (connection_t*)arg;
    char buffer[BUFFER_SIZE];
    int bytes_read;
    
    // 进行SSL握手
    if (SSL_accept(conn->ssl) <= 0) {
        ERR_print_errors_fp(stderr);
        close(conn->client_fd);
        SSL_free(conn->ssl);
        free(conn);
        return NULL;
    }
    
    conn->state = CONN_STATE_AUTHENTICATING;
    
    // 接收客户端认证信息
    bytes_read = SSL_read(conn->ssl, buffer, BUFFER_SIZE - 1);
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("接收到认证数据: %s\n", buffer);
        
        // 解析认证信息（实际应用中应使用更安全的协议）
        char username[MAX_USERNAME_LEN], password[MAX_PASSWORD_LEN];
        if (sscanf(buffer, "AUTH %s %s", username, password) == 2) {
            user_t* user;
            if (authenticate_user(username, password, &user)) {
                // 认证成功，创建会话
                session_t* session = (session_t*)malloc(sizeof(session_t));
                session->session_id = rand();
                session->user = user;
                session->create_time = time(NULL);
                session->last_activity = time(NULL);
                strcpy(session->client_ip, inet_ntoa(((struct sockaddr_in*)conn->ssl->session->sock)->sin_addr));
                sprintf(session->tunnel_ip, "10.100.%d.%d", rand() % 256, rand() % 256);
                session->ssl = conn->ssl;
                
                conn->session = session;
                conn->state = CONN_STATE_AUTHENTICATED;
                
                // 发送认证成功响应
                sprintf(buffer, "AUTH_OK %d %s", session->session_id, session->tunnel_ip);
                SSL_write(conn->ssl, buffer, strlen(buffer));
                
                printf("用户 %s 认证成功，会话ID: %d\n", username, session->session_id);
                
                // 进入数据传输阶段
                conn->state = CONN_STATE_ESTABLISHED;
                
                while (conn->state == CONN_STATE_ESTABLISHED && gateway.running) {
                    bytes_read = SSL_read(conn->ssl, buffer, BUFFER_SIZE);
                    if (bytes_read <= 0) {
                        // 连接关闭或出错
                        break;
                    }
                    
                    // 更新最后活动时间
                    conn->last_packet_time = time(NULL);
                    
                    // 根据连接模式处理数据
                    if (conn->mode == 0) {
                        // 代理模式
                        handle_http_proxy_request(conn, buffer);
                    } else {
                        // 隧道模式
                        handle_tunnel_data(conn, (unsigned char*)buffer, bytes_read);
                    }
                }
            } else {
                // 认证失败
                sprintf(buffer, "AUTH_FAIL");
                SSL_write(conn->ssl, buffer, strlen(buffer));
                printf("用户 %s 认证失败\n", username);
            }
        }
    }
    
    // 清理资源
    if (conn->session) {
        if (conn->session->user) {
            free(conn->session->user);
        }
        free(conn->session);
    }
    
    SSL_shutdown(conn->ssl);
    SSL_free(conn->ssl);
    close(conn->client_fd);
    free(conn);
    
    return NULL;
}

// 创建虚拟网卡（示例函数，实际实现需要根据操作系统进行）
int create_virtual_network_interface(const char* interface_name, const char* ip_address, const char* netmask) {
    // 实际应用中，这里应该调用操作系统API创建虚拟网卡
    // 不同操作系统的实现方式不同
    
    // 这里仅作为示例，返回成功
    printf("创建虚拟网卡 %s，IP地址: %s，子网掩码: %s\n", interface_name, ip_address, netmask);
    return 1;
}

// 数据包封装函数
int packet_encapsulate(const void* packet, int packet_len, void** encapsulated_data, int* encapsulated_len) {
    // 为封装数据分配内存
    *encapsulated_len = packet_len + sizeof(int) + 8; // 添加长度字段和头部
    *encapsulated_data = (void*)malloc(*encapsulated_len);
    if (!*encapsulated_data) {
        return 0;
    }
    
    // 添加封装头部
    memset(*encapsulated_data, 0, *encapsulated_len);
    memcpy(*encapsulated_data, "SSLVPN", 6); // 隧道标识
    
    // 添加长度字段
    int* len_ptr = (int*)((*encapsulated_data) + 6);
    *len_ptr = htonl(packet_len);
    
    // 复制原始数据包
    memcpy(*encapsulated_data + 10, packet, packet_len);
    
    return 1;
}

// 数据包解封装函数
int packet_decapsulate(const void* encapsulated_data, int encapsulated_len, void** packet, int* packet_len) {
    // 检查数据长度
    if (encapsulated_len < 10) {
        return 0;
    }
    
    // 检查隧道标识
    if (memcmp(encapsulated_data, "SSLVPN", 6) != 0) {
        return 0;
    }
    
    // 获取原始数据包长度
    int* len_ptr = (int*)((const char*)encapsulated_data + 6);
    *packet_len = ntohl(*len_ptr);
    
    // 检查长度是否合法
    if (*packet_len <= 0 || *packet_len > encapsulated_len - 10) {
        return 0;
    }
    
    // 分配内存并复制原始数据包
    *packet = (void*)malloc(*packet_len);
    if (!*packet) {
        return 0;
    }
    
    memcpy(*packet, (const char*)encapsulated_data + 10, *packet_len);
    
    return 1;
}

// 启动SSL VPN网关
void start_gateway() {
    printf("SSL VPN网关已启动，等待客户端连接...\n");
    
    while (gateway.running) {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        
        // 接受客户端连接
        int client_fd = accept(gateway.server_fd, (struct sockaddr*)&client_addr, &client_addr_len);
        if (client_fd < 0) {
            if (gateway.running) { // 只有在运行状态下才报错
                perror("接受连接失败");
            }
            continue;
        }
        
        printf("接受到来自 %s:%d 的连接\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        
        // 创建SSL连接
        SSL* ssl = SSL_new(gateway.ssl_ctx);
        SSL_set_fd(ssl, client_fd);
        
        // 创建连接对象
        connection_t* conn = (connection_t*)malloc(sizeof(connection_t));
        conn->conn_id = rand();
        conn->client_fd = client_fd;
        conn->ssl = ssl;
        conn->state = CONN_STATE_CONNECTING;
        conn->session = NULL;
        conn->last_packet_time = time(NULL);
        conn->mode = 0; // 默认代理模式
        
        // 创建线程处理客户端连接
        pthread_t thread_id;
        if (pthread_create(&thread_id, NULL, handle_client, conn) != 0) {
            perror("创建线程失败");
            SSL_free(ssl);
            close(client_fd);
            free(conn);
            continue;
        }
        
        // 分离线程，自动回收资源
        pthread_detach(thread_id);
    }
}

// 主函数
int main(int argc, char* argv[]) {
    int port = 443; // 默认HTTPS端口
    const char* cert_file = "server.crt";
    const char* key_file = "server.key";
    
    // 解析命令行参数
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
            port = atoi(argv[i + 1]);
            i++;
        } else if (strcmp(argv[i], "--cert") == 0 && i + 1 < argc) {
            cert_file = argv[i + 1];
            i++;
        } else if (strcmp(argv[i], "--key") == 0 && i + 1 < argc) {
            key_file = argv[i + 1];
            i++;
        } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
            printf("用法: %s [-p 端口] [--cert 证书文件] [--key 私钥文件] [-h]\n", argv[0]);
            return 0;
        }
    }
    
    // 初始化网关
    init_gateway(port, cert_file, key_file);
    
    // 启动网关服务
    start_gateway();
    
    // 清理资源
    cleanup_gateway();
    
    return 0;
}